package org.power.core.util;

import cn.hutool.core.io.resource.ClassPathResource;
import cn.hutool.db.Session;
import com.google.common.reflect.ClassPath;
import org.apache.commons.io.FileUtils;
import org.power.core.common.CommonResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;

public class PyCmdUtil {
    private static final Logger LOGGER = LoggerFactory.getLogger(PyCmdUtil.class);

    public synchronized static boolean execute(String scriptPath, String args) {
        Process proc;
        try {
            proc = Runtime.getRuntime().exec("python " + scriptPath + " " + args);// 执行py文件
            //用输入输出流来截取结果
            BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
            String line = null;
            int count = 0;
            while ((line = in.readLine()) != null) {
                System.out.println(line);
                count++;
            }
            in.close();
            proc.waitFor(30, TimeUnit.SECONDS);
            return true;
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     *
     * @param python
     * @param scriptPath
     * @param args
     * @return
     */
    public synchronized static boolean excute(String python, String scriptPath, String[] args) {
        LOGGER.info("start to execute python script...");
        ProcessBuilder builder = new ProcessBuilder();
        try {
            String inputDataSet = args[0];
            String usingModel = args[1];
            String outputDataSet = args[2];
            String outputDeviation = args[3];

            String[] arg = new String[]{python, scriptPath, inputDataSet, usingModel, outputDataSet, outputDeviation};

//            System.out.println(Arrays.toString(arg));
            builder.command(arg);
            builder.redirectErrorStream(true);
            Process proc = builder.start();// 执行py文件
            //用输入输出流来截取结果
            BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
            String line;
            // 修改
            int count = 0;
//            String imagePath = "";
            while ((line = in.readLine()) != null) {
//                if (line.startsWith("$$$$$$$$$$")) {
//                    imagePath = line.substring("$$$$$$$$$$".length());
//                }
//                System.out.println(line);
                count++;
            }
            in.close();
            proc.waitFor(30, TimeUnit.SECONDS);
            if (0 == count) {
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < args.length; i++) {
                    sb.append(args[i]).append(" ");
                }
                execute(scriptPath, sb.toString());
            }

//            File file = new File(imagePath);
//            ClassPathResource classPath = new ClassPathResource("static");
//            FileUtils.copyFile(file, new File(classPath.getFile().getPath() + "/GRU.png"));
//            System.out.println(classPath.getFile().getPath());
            LOGGER.info("finish to execute python script...");
            return true;
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        LOGGER.info("finish to execute python script...");
        return false;
    }

    /**
     * 模型训练执行脚本
     *
     * @return
     */
    public synchronized static boolean excuteTrain(String python, String scriptPath, String inputDataSet, String usingModel, String outputModelPath,
                                                   int layerArgv, double dropoutArgv, int denseArgv, String lossArgv, String monitorArgv,
                                                   int patienceArgv, double factorArgv, double min_lrArgv, int batch_sizeArgv,
                                                   int epochsArgv) {
        LOGGER.info("start to execute python script...");
        ProcessBuilder builder = new ProcessBuilder();
        try {
            String[] args = new String[]{python, scriptPath, inputDataSet, usingModel, outputModelPath, String.valueOf(layerArgv),
                    String.valueOf(dropoutArgv), String.valueOf(denseArgv), lossArgv, monitorArgv, String.valueOf(patienceArgv),
                    String.valueOf(factorArgv), String.valueOf(min_lrArgv), String.valueOf(batch_sizeArgv),
                    String.valueOf(epochsArgv)};
            builder.redirectErrorStream(true); // 输出python错误信息
            builder.command(args); // 添加参数
            Process proc = builder.start();// 执行py文件
            //用输入输出流来截取结果
            BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
            String line = null;
            int count = 0;
            while ((line = in.readLine()) != null) {
//                System.out.println(line);
                count++;
            }
            in.close();
            proc.waitFor(30, TimeUnit.SECONDS);
            if (0 == count) {
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < args.length; i++) {
                    sb.append(args[i]).append(" ");
                }
                execute(scriptPath, sb.toString());
            }
            LOGGER.info("finish to execute python script...");

            return true;
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        LOGGER.info("finish to execute python script...");
        return false;
    }

    public static boolean trainModel(String python, String scriptPath, String inputDataSet, String usingModel, String outputModelPath,
                                     int layerArgv, double dropoutArgv, int denseArgv, String lossArgv, String monitorArgv,
                                     int patienceArgv, double factorArgv, double min_lrArgv, int batch_sizeArgv,
                                     int epochsArgv) {
        LOGGER.info("训练模型: {} {} {} {}", scriptPath, inputDataSet, usingModel, outputModelPath);
        excuteTrain(python, scriptPath, inputDataSet, usingModel, outputModelPath, layerArgv, dropoutArgv, denseArgv,
                lossArgv, monitorArgv, patienceArgv, factorArgv, min_lrArgv, batch_sizeArgv, epochsArgv);
        return true;
    }

    public static boolean predictModel(String usingModelPath) {
        String python = "D:\\PycharmProjects\\power\\venv\\Scripts\\python.exe";
        String scriptPath = "D:\\data\\power\\script\\PredictModel.py";
        String inputDataSet = "D:\\data\\power\\power\\file\\feature.csv";
        String outputDataSet = "D:\\data\\power\\file\\feature_output_GRU.csv";
        String outputDeviation = "D:\\data\\power\\file\\feature_output_deviation_GRU.csv";
        return excute(python, scriptPath, new String[]{inputDataSet, "D:\\data\\power\\model\\GRU.h5", outputDataSet, outputDeviation});
    }

    public static boolean predictModel(String inputDataSet, String usingModelPath) {
        String python = "D:\\PycharmProjects\\power\\venv\\Scripts\\python.exe";
        String scriptPath = PyCmdUtil.class.getClassLoader().getResource(".").getPath() + "PredictModel.py";
        String outputDataSet = "/Users/mylovin/Downloads/power/test_output5_850.csv";
        return excute(python, scriptPath, new String[]{inputDataSet, usingModelPath, outputDataSet});
    }

    public static boolean predictModel(String python, String scriptPath, String inputDataSet, String usingModelPath, String outputDataSet, String outputDeviation) {
        LOGGER.info("预测模型: {} {} {} {}, {}", scriptPath, inputDataSet, usingModelPath, outputDataSet, outputDeviation);
        return excute(python, scriptPath, new String[]{inputDataSet, usingModelPath, outputDataSet, outputDeviation});
    }

    /*public static void main(String[] args) {
        //PyCmdUtil.predictModel("");
        PyCmdUtil.trainModel("/data/power/script/TrainModel.py",
                "/data/power/file/feature.csv", "LSTM",
                "/data/power/model/LSTM_20220223162310.h5",
                32, 0.2, 6, "mae", "val_loss",
                3, 0.5, 0.00001,
                64, 100);
    }*/
}
